home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Mac Game Programming Gurus
/
TricksOfTheMacGameProgrammingGurus.iso
/
More Source
/
Pascal
/
Book Demos in Pascal
/
SpriteEngine
/
SpriteEngine.p
< prev
next >
Wrap
Text File
|
1995-04-04
|
6KB
|
215 lines
program SpriteEngine;
uses
{$IFC UNDEFINED THINK_PASCAL}
Types, QuickDraw, Fonts, Events, Packages, Menus, Dialogs, Windows,{}
OSUtils, ToolUtils, OSEvents, Resources,
{$ENDC}
QDOffScreen, SpriteStructure, SpriteTools, SpriteHandlers;
{SpriteEngine}
{============}
{This demo sprite engine is designed for the following structure:}
{(Lower units use the higher ones.)}
{}
{SpriteTools.c: Utilities for loading and drawing}
{|}
{SpriteHanders.c: All custom code: Sprite init, movement, collisions}
{|}
{SpriteEngine.c: Main program, sprite engine}
{The only files you need to edit in order to change the sprite behavior are}
{the files SpriteHandlers.c and SpriteHandlers.h.}
(* The actual sprite engine *)
procedure InitSpriteEngine (var offBounds: Rect; backgroundPictureID: Integer);
var
backgroundPicture: PicHandle;
saveGD: GDHandle;
savePort: GWorldPtr;
begin
MyNewGWorld(gOffScreen, offBounds);
MyNewGWorld(gBackScreen, offBounds);
GetGWorld(savePort, saveGD); (*Save the port/device*)
SetGWorld(GWorldPtr(gBackScreen), nil);
EraseRect(offBounds);
backgroundPicture := GetPicture(backgroundPictureID);
if (backgroundPicture <> nil) then
begin
DrawPicture(backgroundPicture, offBounds);
ReleaseResource(Handle(backgroundPicture));
end;
SetGWorld(GWorldPtr(gOffScreen), nil);
CopyBits(gBackScreen^.portBits, gOffScreen^.portBits, offBounds, offBounds, srcCopy, nil);
SetGWorld(GWorldPtr(myWindow), GetMainDevice);
CopyBits(gOffScreen^.portBits, myWindow^.portBits, offBounds, offBounds, srcCopy, nil);
SetGWorld(savePort, saveGD);
end; (*InitSpriteEngine*)
procedure RunSpriteEngine;
const
kWallBounce = 7;(*1/10-ths of speed kept after wallbounce*)
kBallDiameterSquared = (32 * 32);(*Diameter 32, squared*)
var
tmpRect: Rect;
saveGD: GDHandle;
savePort: GWorldPtr;
theSprite, anotherSprite: SpritePtr;
bounds1, bounds2: Rect;
begin
GetGWorld(savePort, saveGD); (*Save the port/device*)
(*1: Erase all sprites from gOffScreen*)
(*Note: We keep the rectangles for erasing on the screen, later.*)
SetGWorld(GWorldPtr(gOffScreen), nil);
theSprite := gSpriteList;
while (theSprite <> nil) do
begin
theSprite^.drawingRect := theSprite^.face^.portRect;
OffsetRect(theSprite^.drawingRect, theSprite^.position.h, theSprite^.position.v);
CopyBits(gBackScreen^.portBits, gOffScreen^.portBits, theSprite^.drawingRect, theSprite^.drawingRect, srcCopy, nil);
theSprite := theSprite^.next;
end;
(*2: Change the position and speed*)
theSprite := gSpriteList;
while (theSprite <> nil) do
begin
MoveSprite(theSprite);
theSprite := theSprite^.next;
end;(*position/speed loop*)
(*3: Check for collisions*)
theSprite := gSpriteList;
while (theSprite <> nil) do (*For all sprites in the list…*)
begin
bounds1 := theSprite^.face^.portRect;
OffsetRect(bounds1, theSprite^.position.h, theSprite^.position.v);
anotherSprite := theSprite^.next;
while (anotherSprite <> nil) do
(*compare its position to all following sprites*)
begin
bounds2 := anotherSprite^.face^.portRect;
OffsetRect(bounds2, anotherSprite^.position.h, anotherSprite^.position.v);
if (SectRect(bounds1, bounds2, tmpRect)) then
HitSprite(theSprite, anotherSprite);
anotherSprite := anotherSprite^.next;
end;
theSprite := theSprite^.next;
end; (*collision loop*)
(*4: Draw sprites in gOffScreen*)
(*Note: PlotCIcon or DrawPicture are not very fast! We can speed it up my*)
(*pre-drawing them in some offscreen, and CopyBits them from there.*)
theSprite := gSpriteList;
while (theSprite <> nil) do (*For all sprites in the list…*)
begin
tmpRect := theSprite^.face^.portRect;
OffsetRect(tmpRect, theSprite^.position.h, theSprite^.position.v);
PlotFace(theSprite^.face, gOffScreen, tmpRect.topLeft);
theSprite := theSprite^.next;
end;
(*5: Copy sprites to the screen (gWind) - both old and new position!*)
(*Note: Depending on what limitations we have on movement, we may be able to avoid the multiple*)
(*CopyBitsing here. E.g. if sprites always move a maximum of 2 pixels, we can copy a 2 pixels*)
(*larger area, etc.*)
SetGWorld(GWorldPtr(myWindow), saveGD);
theSprite := gSpriteList;
while (theSprite <> nil) do (*For all sprites in the list…*)
begin
CopyBits(gOffScreen^.portBits, myWindow^.portBits, theSprite^.drawingRect, theSprite^.drawingRect, srcCopy, nil);
theSprite^.drawingRect := theSprite^.face^.portRect;
OffsetRect(theSprite^.drawingRect, theSprite^.position.h, theSprite^.position.v);
CopyBits(gOffScreen^.portBits, myWindow^.portBits, theSprite^.drawingRect, theSprite^.drawingRect, srcCopy, nil);
theSprite := theSprite^.next;
end;
SetGWorld(savePort, saveGD);
end; (*RunSpriteEngine*)
(* Standard inits *)
procedure InitToolbox;
begin
{$IFC UNDEFINED THINK_PASCAL}
InitGraf(@qd.thePort);
InitFonts;
FlushEvents(everyEvent, 0);
InitWindows;
InitMenus;
TEInit;
InitDialogs(nil);
{$ENDC}
InitCursor;
end; (*InitToolbox*)
(* Initialize - create window, load graphics *)
procedure InitStuff;
var
windowRectangle: Rect;
(*Set up the window*)
begin
SetRect(windowRectangle, 50, 50, 450, 350);
myWindow := NewCWindow(nil, windowRectangle, 'Sprite test', true, documentProc, WindowPtr(-1), false, 0);
SetPort(myWindow);
{$IFC UNDEFINED THINK_PASCAL}
qd.randSeed := TickCount; (*Seed the random number generator*)
{$ELSEC}
randSeed := TickCount; (*Seed the random number generator*)
{$ENDC}
end; (*InitStuff*)
const
kBackgroundPictureID = 128;
(* Main program *)
var
startTime: LongInt;
begin
InitToolbox;
InitStuff;
InitSpriteEngine(myWindow^.portRect, kBackgroundPictureID);
InitSprites;
{HideCursor;}
while not Button do
begin
startTime := TickCount;
RunSpriteEngine;
while TickCount < startTime + kFrameTime do
;
end;
{ShowCursor;}
FlushEvents(mDownMask, 0);
end. (*main*)